// @Author EthanScriptOn
// @Desc
package filter

import (
	"context"
	"gitee.com/fatzeng/srf_switch/core/switch_subject"
	"gitee.com/fatzeng/srf_switch/core/switch_subject/statistics"
	"gitee.com/fatzeng/srf_switch_basic_components/switch_log"
	"reflect"
	"sync"
)

type DefaultSrfSwitchFactor struct {
	middleware             switch_subject.CacheMiddleware
	storeLock              *sync.Mutex
	factorActuatorRegistry switch_subject.FactorActuatorRegistry
}

func GenerateDefaultSrfSwitchFactor(factorActuatorRegistry switch_subject.FactorActuatorRegistry, middleware switch_subject.CacheMiddleware) *DefaultSrfSwitchFactor {
	return &DefaultSrfSwitchFactor{
		middleware:             middleware,
		factorActuatorRegistry: factorActuatorRegistry,
		storeLock:              &sync.Mutex{},
	}
}

func (d *DefaultSrfSwitchFactor) Filter(ctx context.Context, rule interface{}) bool {
	value := ctx.Value(switch_subject.STATISTIC)
	statisticItem := value.(*statistics.SwitchStatistic)
	item := new(statistics.SwitchStatisticItem)
	statisticItem.Items = append(statisticItem.Items, item)
	ruleValue := reflect.ValueOf(rule)
	if ruleValue.Kind() == reflect.Ptr && !ruleValue.IsNil() {
		ruleValue = ruleValue.Elem()
	}
	factorRule, ok := ruleValue.Interface().(*switch_subject.FactorRule)
	if !ok {
		item.FactorId = "DefaultFactorId"
		item.IsPassThrough = false
		switch_log.Logger().Warn("rule is not FactorRule")
		return false
	}
	isHitCache, ruleState := d.middleware.IsHitCache(ctx, factorRule)
	if isHitCache {
		statisticItem.Remark = "hit middleware!"
		return ruleState
	}
	actuatorFun := d.factorActuatorRegistry[factorRule.FactorId]
	if actuatorFun == nil {
		item.IsPassThrough = false
		switch_log.Logger().Warn("Unable to find factor with ID:", factorRule.FactorId)
		return false
	}
	funRes, err := actuatorFun(ctx, factorRule.RuleRemark)
	if err != nil {
		item.IsPassThrough = false
		switch_log.Logger().Error("error executing factor for:", factorRule.FactorId, err.Error())
		return false
	}
	item.IsPassThrough = funRes
	d.middleware.PutCache(ctx, factorRule, funRes)
	return funRes
}
